package org.concepts.java.antlr.csv;

import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;

/**
 * Parser for CSV file. A sample CSV file will look like the following:
 * <p/>
 * 
 * <code>
 * /*<br/>
 *   This is a sample CSV file.
 *   <br/><br/>
 *   The file contains a comma separated list of integers<br/><br/>
 *   A line of CSV is a record. Thus, there are three records in this file<br/><br/> 
 * *&#47;<br/><br/>
 * 1,2,3<br/>
 * // Single line comment<br/>
 * 10, 11,12<br/>
 * &nbsp;&nbsp;100,101,    102<br/>
 * </code>
 * 
 * <p/>
 * <p/>
 * <p/>
 * 
 * 
 * The CSV file must follow the following rules:
 * <p/>
 * 
 * <ol>
 * <li>Comma separated list of positive integers</li>
 * <li>Single and multi line comments can be put in using the same syntax as
 * Java ( '//' for single line '/*' and '*&#47;' for multi line ')</li>
 * <li>White space (space or tab) should be ignored</li>
 * <li>Each CSV line is a record. Records end with a new line or end of file.</li>
 * <li>Parser should be tolerant to user errors. Any line/record containing
 * errors (E.g. invalid character) should be ignored and an appropriate error
 * message should be sent to the error stream. The error message should indicate
 * the line and column number of the error.</li>
 * </ol>
 * 
 * @author vvvv
 * 
 */
public class CSV {

  private String data = null;
  
  private CSVLexer csvLexer = null;
  
  private CSVParser csvParser = null;

  /**
   * Creates CSV with the data that needs to be parsed.
   * 
   * @param data
   *          Data. Cannot be null.
   */
  public CSV(String data) {
    if (data == null) {
      throw new IllegalArgumentException("Data cannot be null");
    }
    System.out.println("\n\nCSV input [" + data + "]");
    this.data = data;
    parse();
  }
  
  /**
   * Parses the data.
   */
  private void parse() {
    this.csvLexer = new CSVLexer(new ANTLRStringStream(this.data));
    this.csvParser = new CSVParser(new CommonTokenStream(this.csvLexer));
    try {
      this.csvParser.file();
    } catch (RecognitionException e) {
      e.printStackTrace();
    }
    
    // Output result
    System.out.println("Number of records: " + this.getRecordCount());
    for (int recCnt = 0; recCnt < this.getRecordCount() ; recCnt++) {
      int[] record = this.getRecord(recCnt);
      System.out.print("Record " + recCnt+ ": ");
      for (int col : record) {
       System.out.print("[" + col + "]");
      }
      System.out.println("");
    }
    System.out.println("");
  }
  
  /**
   * Get the number of records in the CSV file.
   *  
   * @return
   */
  public int getRecordCount() {
    return this.csvParser.getRecordCount();
  }
  
  /**
   * Returns an array of integers for the given record.  
   *  
   * @param counter record counter. E.g. If there are 3 records, then
   * valid counter are 0,1,2
   * @return array of integer. Is null if invalid counter is passed in.
   */
  public int[] getRecord(int counter)  {
    if (!(counter >= 0 & counter < getRecordCount())) {
      return null;
    }
   return this.csvParser.getRecord(counter); 
  }

}
